package org.halk.util;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.monitor.FileAlterationListener;
import org.apache.commons.io.monitor.FileAlterationMonitor;
import org.apache.commons.io.monitor.FileAlterationObserver;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.yaml.snakeyaml.Yaml;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.Map;

/**
 * 监听加节日自定义配置文件
 *
 * @Author halk
 * @Date 2023/4/25 21:20
 **/
@Component
@Slf4j
public class FileMonitorListener implements FileAlterationListener {

    /**
     * 需要监控的文件，可以是任意路径下的文件
     */
    @Value("${halk.monitor.path}")
    private String monitorPath;
    @Value("${halk.monitor.name}")
    private String monitorName;

    @PostConstruct
    public void init() {
        try {
            String pathname = monitorPath + monitorName;
            File file = new File(pathname);
            if (!file.exists()) {
                log.error("需要监控的配置文件不存在！位置：{}", pathname);
            } else {
                reloadFile(file);
            }
            try {
                // 构造观察类主要提供要观察的目录，当然还有详细信息的filter
                FileAlterationObserver observer = new FileAlterationObserver(monitorPath);
                // 为观察对象添加收听对象
                observer.addListener(this);
                // 配置Monitor，第一个参数单位是毫秒，是监听间隔；第二个参数就是绑定我们之前的观察对象。
                FileAlterationMonitor fileMonitor = new FileAlterationMonitor(1000, observer);
                // 启动监听
                fileMonitor.start();
                log.info("FileMonitor started successfully for path: {}", pathname);
            } catch (Exception e) {
                log.error("fileMonitor start error", e);
            }
        } catch (Exception e) {
            log.error("需要监控的配置文件读取失败：{}", e.getMessage());
        }
    }

    @Override
    public void onStart(FileAlterationObserver fileAlterationObserver) {
        log.info("fileMonitor start");
    }

    @Override
    public void onDirectoryCreate(File directory) {
        log.info("Directory created: {}", directory.getPath());
    }

    @Override
    public void onDirectoryChange(File directory) {
        log.info("Directory changed: {}", directory.getPath());
    }

    @Override
    public void onDirectoryDelete(File directory) {
        log.info("Directory deleted: {}", directory.getPath());
    }

    @Override
    public void onFileCreate(File file) {
        log.info("File created: {}", file.getPath());
    }

    @Override
    public void onFileChange(File file) {
        log.info("file change. path:{}", file.getPath());
        if (file.getAbsolutePath().contains(monitorName)) {
            log.info("需要监控的文件改变！path:{}", file.getPath());
            reloadFile(file);
        } else {
            log.info("文件路径不匹配: {}", file.getPath());
        }
    }

    @Override
    public void onFileDelete(File file) {
        log.info("File deleted: {}", file.getPath());
    }

    @Override
    public void onStop(FileAlterationObserver observer) {
        log.info("fileMonitor stop");
    }

    /**
     * 处理改变的文件
     *
     * @param file
     */
    private static void reloadFile(File file) {
        Yaml yaml = new Yaml();
        try (FileInputStream inputStream = new FileInputStream(file)) {
            Map<String, Object> data = yaml.load(inputStream);
            log.info("配置文件重新加载! 时间：{} value: {}", DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"), data);

            // 获取嵌套的配置项
            Map<String, Object> halkConfig = (Map<String, Object>) data.get("halk");
            if (halkConfig != null) {
                Map<String, Object> xiaomingConfig = (Map<String, Object>) halkConfig.get("xiaoming");
                if (xiaomingConfig != null) {
                    Object age = xiaomingConfig.get("age");
                    log.info("配置文件重新加载! 时间：{}, name: {},  age: {}，sex: {}", DateUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss"),xiaomingConfig.get("name"), age, xiaomingConfig.get("sex"));
                } else {
                    log.error("配置文件中未找到 halk.xiaoming 配置项！");
                }
            } else {
                log.error("配置文件中未找到 halk 配置项！");
            }
        } catch (FileNotFoundException e) {
            log.error("需要监控的配置文件不存在！位置：{}", file.getPath());
        } catch (IOException e) {
            log.error("读取配置文件时发生错误！位置：{}", file.getPath(), e);
        }
    }
}
